/* src/interfaces/ecpg/pgtypeslib/common.c */

#include "postgres_fe.h"

#include "pgtypes.h"
#include "pgtypeslib_extern.h"

/* 返回值为零填充。 */
char * pgtypes_alloc(long fc_size)
{
	char	   *fc_new = (char *) calloc(1L, fc_size);

	if (!fc_new)
		errno = ENOMEM;
	return fc_new;
}

char * pgtypes_strdup(const char *fc_str)
{
	char	   *fc_new = (char *) strdup(fc_str);

	if (!fc_new)
		errno = ENOMEM;
	return fc_new;
}

int pgtypes_fmt_replace(union un_fmt_comb fc_replace_val, int fc_replace_type, char **fc_output, int *fc_pstr_len)
{
	/*
	 * 通用变量，设置为0以修复编译器警告
	 */
	int			fc_i = 0;

	switch (fc_replace_type)
	{
		case PGTYPES_TYPE_NOTHING:
			break;
		case PGTYPES_TYPE_STRING_CONSTANT:
		case PGTYPES_TYPE_STRING_MALLOCED:
			fc_i = strlen(fc_replace_val.str_val);
			if (fc_i + 1 <= *fc_pstr_len)
			{
				/* 在我们复制的内容中包含尾部终止符 */
				memcpy(*fc_output, fc_replace_val.str_val, fc_i + 1);
				*fc_pstr_len -= fc_i;
				*fc_output += fc_i;
				if (fc_replace_type == PGTYPES_TYPE_STRING_MALLOCED)
					free(fc_replace_val.str_val);
				return 0;
			}
			else
				return -1;
			break;
		case PGTYPES_TYPE_CHAR:
			if (*fc_pstr_len >= 2)
			{
				(*fc_output)[0] = fc_replace_val.char_val;
				(*fc_output)[1] = '\0';
				(*fc_pstr_len)--;
				(*fc_output)++;
				return 0;
			}
			else
				return -1;
			break;
		case PGTYPES_TYPE_DOUBLE_NF:
		case PGTYPES_TYPE_INT64:
		case PGTYPES_TYPE_UINT:
		case PGTYPES_TYPE_UINT_2_LZ:
		case PGTYPES_TYPE_UINT_2_LS:
		case PGTYPES_TYPE_UINT_3_LZ:
		case PGTYPES_TYPE_UINT_4_LZ:
			{
				char	   *fc_t = pgtypes_alloc(PGTYPES_FMT_NUM_MAX_DIGITS);

				if (!fc_t)
					return ENOMEM;
				switch (fc_replace_type)
				{
					case PGTYPES_TYPE_DOUBLE_NF:
						fc_i = snprintf(fc_t, PGTYPES_FMT_NUM_MAX_DIGITS,
									 "%0.0g", fc_replace_val.double_val);
						break;
					case PGTYPES_TYPE_INT64:
						fc_i = snprintf(fc_t, PGTYPES_FMT_NUM_MAX_DIGITS,
									 INT64_FORMAT, fc_replace_val.int64_val);
						break;
					case PGTYPES_TYPE_UINT:
						fc_i = snprintf(fc_t, PGTYPES_FMT_NUM_MAX_DIGITS,
									 "%u", fc_replace_val.uint_val);
						break;
					case PGTYPES_TYPE_UINT_2_LZ:
						fc_i = snprintf(fc_t, PGTYPES_FMT_NUM_MAX_DIGITS,
									 "%02u", fc_replace_val.uint_val);
						break;
					case PGTYPES_TYPE_UINT_2_LS:
						fc_i = snprintf(fc_t, PGTYPES_FMT_NUM_MAX_DIGITS,
									 "%2u", fc_replace_val.uint_val);
						break;
					case PGTYPES_TYPE_UINT_3_LZ:
						fc_i = snprintf(fc_t, PGTYPES_FMT_NUM_MAX_DIGITS,
									 "%03u", fc_replace_val.uint_val);
						break;
					case PGTYPES_TYPE_UINT_4_LZ:
						fc_i = snprintf(fc_t, PGTYPES_FMT_NUM_MAX_DIGITS,
									 "%04u", fc_replace_val.uint_val);
						break;
				}

				if (fc_i < 0 || fc_i >= PGTYPES_FMT_NUM_MAX_DIGITS)
				{
					free(fc_t);
					return -1;
				}
				fc_i = strlen(fc_t);
				*fc_pstr_len -= fc_i;

				/*
				 * 如果 *pstr_len == 0，我们没有足够的空间来容纳
				 * 终止符，转换失败
				 */
				if (*fc_pstr_len <= 0)
				{
					free(fc_t);
					return -1;
				}
				strcpy(*fc_output, fc_t);
				*fc_output += fc_i;
				free(fc_t);
			}
			break;
		default:
			break;
	}
	return 0;
}

/* 在pgtypes.h中声明的函数。 */

/* 仅释放内存（主要用于Windows） */
void PGTYPESchar_free(char *fc_ptr)
{
	free(fc_ptr);
}
